#pragma once
#include<muduo/net/TcpClient.h>
#include<muduo/net/TcpServer.h>
#include<muduo/net/EventLoop.h>
#include<muduo/net/EventLoopThread.h>
#include<muduo/base/CountDownLatch.h>
#include<muduo/net/InetAddress.h>
#include"buffer.hpp"
#include"logger.hpp"
#include"message.hpp"
#include"protocol.hpp"

// 连接管理
class BaseConnection
{
public:
    using ptr = std::shared_ptr<BaseConnection>;

    BaseConnection() {}
    virtual ~BaseConnection() {}

    virtual void send(const std::string& out) = 0;
    virtual void close() = 0;
    virtual bool connected() = 0;
    virtual std::string perrAddressString() = 0;
    virtual std::string localAddressString() = 0;

    virtual Address perrAddress() = 0;
    virtual Address localAddress() = 0;

};

class MuduoConnection : public BaseConnection
{
public:
    using ptr = std::shared_ptr<MuduoConnection>;

    MuduoConnection(muduo::net::TcpConnectionPtr connPtr)
        :_conn(connPtr) {}
    virtual ~MuduoConnection() {}

    virtual void send(const std::string& msg) override {
       if (_conn) 
       _conn->send(msg);
       else
       {
            LOG_ERROR << "连接为空";
       }
    }
    virtual void close() override {
        if (_conn) _conn->shutdown();
        else
       {
            LOG_DEBUG << "连接为空";
       }
    }
    virtual bool connected() override{
       if (_conn) return _conn->connected();
       else
       {
            LOG_DEBUG << "连接为空";
            return false;
       }
    }
    virtual std::string perrAddressString() override {
       if (_conn) return _conn->peerAddress().toIpPort();
       else
       {
            LOG_DEBUG << "连接为空";
            return std::string();
       }
    }
    virtual std::string localAddressString() override {
        if (_conn) return _conn->localAddress().toIpPort();
        else
       {
            LOG_DEBUG << "连接为空";
            return std::string();
       }
    }

    virtual Address perrAddress() override
    {
        auto addr = _conn->peerAddress();
        return Address(addr.toIp(), addr.port());
    }

    virtual Address localAddress() override
    {
        auto addr = _conn->localAddress();
        return Address(addr.toIp(), addr.port());        
    }

private:
    muduo::net::TcpConnectionPtr _conn; 
};

class ConnectionFactory
{
public:
    template<typename T, typename ...Args>
    static BaseConnection::ptr create(Args&& ...args)
    {
        return std::make_shared<T>(std::forward<Args>(args)...);
    }
};


// 服务端 --- 客户端
using Conn_cb = std::function<void(BaseConnection::ptr)>;
using OnMess_cb = std::function<void(BaseConnection::ptr, BaseMessage::ptr, BaseProtocol::ptr)>;
using Close_cb = std::function<void(BaseConnection::ptr)>;

class BaseNet
{
public:
    using ptr = std::shared_ptr<BaseNet>;
    BaseNet() {}
    virtual ~BaseNet() {}

    void setConnCb(const Conn_cb& cb) {_conn_cb = cb;}
    void setMessageHander(const OnMess_cb& cb) {_mess_cb = cb;}
    void setCloseCb(const Close_cb& cb) {_close_cb = cb;}

    virtual void start() = 0;
    virtual bool setIoThreads(uint8_t io_threads) {}; 
    virtual BaseConnection::ptr getClientConnection() {};

    //设置应用层的数据处理协议
    virtual void setHandlerProtocol(const BaseProtocol::ptr protocol) {_protocol = protocol;}
     virtual BaseProtocol::ptr getHandlerProtocol() {return _protocol;};

protected:
    Conn_cb _conn_cb;
    OnMess_cb _mess_cb;
    Close_cb _close_cb;
    BaseProtocol::ptr _protocol; // 解耦
};

class BaseNetMuduo : public BaseNet
{
public:
    using ptr = std::shared_ptr<BaseNetMuduo>;
    BaseNetMuduo() {}
    virtual ~BaseNetMuduo() {}

    void onMessage(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buffer, muduo::Timestamp)
    {
        BaseConnection::ptr connection = ConnectionFactory::create<MuduoConnection>(conn);
        BaseBuffer::ptr buf = BufferFactory::creat<MuduoBuffer>(buffer);

        while (_protocol->canProcessed(buf))
        {
            auto msg = _protocol->getOneMessage(buf);
            if (msg)
            {
                // 成功从缓冲区拿出一条合规的数据
                if (_mess_cb) _mess_cb(connection, msg, getHandlerProtocol());
                else LOG_WARN << "暂未设置消息处理回调！";
            }
            else
            {
                LOG_FATAL<< "缓冲区的数据不合规, 关闭连接" << connection->perrAddressString();
                connection->close();
            }
        }
        LOG_DEBUG << "缓冲区的数据不够";
    }

    virtual void onConnect(const muduo::net::TcpConnectionPtr& conn)
    {
            conn->setCloseCallback(std::bind(&BaseNetMuduo::closeCb, this, std::placeholders::_1));
            BaseConnection::ptr connection = ConnectionFactory::create<MuduoConnection>(conn);
            if (_conn_cb) _conn_cb(connection); 
    }

    void closeCb(const muduo::net::TcpConnectionPtr& conn)
    {
        BaseConnection::ptr connection = ConnectionFactory::create<MuduoConnection>(conn);
        if (_close_cb) _close_cb(connection);
    }
};

// -------------- 服务端 -------------------
class MuduoServer : public BaseNetMuduo
{
public:
    using ptr = std::shared_ptr<MuduoServer>;
    virtual ~MuduoServer() {}

    MuduoServer(const std::string& ip, const uint16_t port, const std::string& name, bool reusePort = true)
        :_eventLoop(new muduo::net::EventLoop()) 
        {
            auto flag = muduo::net::TcpServer::Option::kNoReusePort;
            if (reusePort)
            {
                flag = muduo::net::TcpServer::Option::kReusePort;
            }
            _ser = std::make_shared<muduo::net::TcpServer>(_eventLoop.get(), muduo::net::InetAddress(ip, port), name, flag);
            if (_ser)
            {
                _ser->setConnectionCallback(std::bind(&MuduoServer::onConnect, this, std::placeholders::_1));
                _ser->setMessageCallback(std::bind(&MuduoServer::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            }
        }

    // typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
    // typedef std::function<void (const TcpConnectionPtr&, Buffer*, Timestamp)> MessageCallback;
    bool setIoThreads(uint8_t io_threads)
    {
        if (_ser)
        {
            _ser->setThreadNum(io_threads); // 除主线程外，另外的IO线程数 // 内部会调用 EventLoopThreadPool::setThreadNum()
            if (io_threads > 0)
            {
                _latch = std::make_unique<muduo::CountDownLatch>(io_threads);
                // typedef std::function<void(EventLoop*)> ThreadInitCallback;
                _ser->setThreadInitCallback(std::bind(&MuduoServer::thiredInitCallback, this, std::placeholders::_1));
            }
            return true;
        }
        return false;
    }

    virtual void start() override
    {
        _ser->start();
        _latch->wait(); // 阻塞等待所以线程初始化完后继续
        _eventLoop->loop();
    }
private:
    void thiredInitCallback(muduo::net::EventLoop*)
    {
        _latch->countDown(); // -1
    }
private:
    std::unique_ptr<muduo::net::EventLoop> _eventLoop; // 事件循环监控
    std::shared_ptr<muduo::net::TcpServer> _ser;
    std::unique_ptr<muduo::CountDownLatch> _latch; // 多线程同步计数器
};

// ----- 客户端 --------
class MuduoClient : public BaseNetMuduo
{
public:
    using ptr = std::shared_ptr<MuduoClient>;
    MuduoClient() {}
    virtual ~MuduoClient() {}

    MuduoClient(const std::string& serverIP, const uint16_t port, const std::string& name)
        : _loopThread()
        , _client(new muduo::net::TcpClient(_loopThread.startLoop(), muduo::net::InetAddress(serverIP, port), name))
        {
            if (_client)
            {
                _client->setConnectionCallback(std::bind(&MuduoClient::onConnect, this, std::placeholders::_1));
                _client->setMessageCallback(std::bind(&MuduoClient::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            }
        }

    virtual void start() override
    {
        _client->connect();
    }

    virtual BaseConnection::ptr getClientConnection() override
    {
        auto conn  =  ConnectionFactory::create<MuduoConnection>(_client->connection());
        if (conn == nullptr)
        {
            LOG_DEBUG << "创建连接对象失败";
        }
        if (conn->connected())
        {
            LOG_DEBUG << "存在连接";
        }
        else
        {
            LOG_DEBUG << "连接不存在";
        }

        return conn;
    }


    // 确保连接建立时获取 连接
    virtual void onConnect(const muduo::net::TcpConnectionPtr& conn)
    {
        _conn = conn;
        conn->setCloseCallback(std::bind(&BaseNetMuduo::closeCb, this, std::placeholders::_1));
        BaseConnection::ptr connection = ConnectionFactory::create<MuduoConnection>(conn);
        if (_conn_cb) _conn_cb(connection); 
    }

private:
    muduo::net::EventLoopThread _loopThread;
    std::unique_ptr<muduo::net::TcpClient> _client;
    muduo::net::TcpConnectionPtr _conn;
};

// 工厂
class NetFactory
{
public:
    template<typename T, typename ...Args>
    static BaseNet::ptr creater(Args&& ...args)
    {
        return std::make_shared<T>(std::forward<Args>(args)...);
    }
};
